#!/usr/bin/perl -T

################################################################################
# partition_balancer - Script to assist in (re)balancing MySQL partitions.
#
# @author  Ryan Lowe <rlowe@pablowe.net>
# @date    2009-05-25
# @license GPL v2
################################################################################

use strict;
use warnings FATAL => 'all';
use Pod::Usage;
use Getopt::Long;
use English qw(-no_match_vars);
use DBI;

my $VERSION = '0.0.1';
my %OPTIONS;

################################################################################
# Get configuration information
################################################################################

# Parse command line opts
my $gop=new Getopt::Long::Parser;
$gop->configure('no_ignore_case','bundling');
if (!$gop->getoptions(
    'column|c=s'   => \$OPTIONS{ 'column'   },
    'database|d=s' => \$OPTIONS{ 'database' },
    'help|h'       => \$OPTIONS{ 'help'     },
    'host|H=s'     => \$OPTIONS{ 'host'     },
    'password|p=s' => \$OPTIONS{ 'password' },
    'port|P=i'     => \$OPTIONS{ 'port'     },
    'rows|r=i'     => \$OPTIONS{ 'rows'     },
    'socket|s=s'   => \$OPTIONS{ 'socket'   },
    'table|t=s'    => \$OPTIONS{ 'table'    },
    'username|u=s' => \$OPTIONS{ 'user'     },
    'verbose|v+'   => \$OPTIONS{ 'verbose'  },
    'version|V'    => \$OPTIONS{ 'version'  } ) ) {

    pod2usage(2);
}

# Help if asked for or no check given
pod2usage(2) if     ($OPTIONS{'help'});
pod2usage(2) unless ($OPTIONS{'database'});
pod2usage(2) unless ($OPTIONS{'rows'});
pod2usage(2) unless ($OPTIONS{'table'});

# Yay for versions
if ($OPTIONS{'version'}) {
    print "$VERSION\n";
    exit 0;
}

# Set global defaults/validate options
$OPTIONS{'hostname'} = $OPTIONS{'hostname'} ? 
    $OPTIONS{'hostname'} : 'localhost';
$OPTIONS{'verbose'} = $OPTIONS{'verbose'} ? 
    $OPTIONS{'verbose'} : 0;
$OPTIONS{'port'} = $OPTIONS{'port'} ?
    $OPTIONS{'port'} : 3306;

################################################################################
# Begin the main program
################################################################################

# Attempt db connection
my $connection_string  = 'DBI:mysql:';
$connection_string    .= "host=$OPTIONS{'host'};";
$connection_string    .= "database=$OPTIONS{'database'};"
    if $OPTIONS{'database'};
$connection_string    .= "mysql_socket=$OPTIONS{'socket'};"
    if $OPTIONS{'socket'} and $OPTIONS{'host'} eq 'localhost';
$connection_string    .= "port=$OPTIONS{'port'};";
$connection_string    .= "mysql_multi_statements=1";
my $dbh;
eval {
    $dbh = DBI->connect ( 
        $connection_string,
        $OPTIONS{'user'},
        $OPTIONS{'password'},
        { RaiseError => 1, PrintError => 0 } 
    );
};

if ( $@ ) {
    print "Could not connect to MySQL";
    print ': '.$@ if ($OPTIONS{'verbose'} > 0);
    exit 1;
}


################################################################################
# Documentation
################################################################################
 
=pod

=head1 NAME

partition_balancer - Script to assist in (re)balancing MySQL partitions.

=head1 SYNOPSIS

 partition_balancer [options] -d <database> -r <rows> -t <table> 

 Options:
   -c, --column=<column>     The column on which partitioning is based
   -d, --database=<dbname>   The database to use
   -h, --help                Display this message and exit
   -H, --host=<hostname>     The target MySQL server host
   -p, --password=<password> The password of the MySQL user
   -P, --port=<portnum>      The port MySQL is listening on
   -r, --rows=<numrows>      The target number of rows in each partition
   -s, --socket=<sockfile>   Use the specified mysql unix socket to connect
   -t, --table=<table>       The table name to evaluate
   -u, --username=<username> The MySQL user used to connect
   -v, --verbose             Increase verbosity level
   -V, --version             Display version information and exit

 Defaults are:

 ATTRIBUTE                  VALUE
 -------------------------- ---------------------
 column                     Current partition key
 database                   No default value
 help                       FALSE
 host                       localhost
 password                   No default value
 port                       3306
 rows                       No default value
 socket                     No default value
 table                      No default value
 username                   No default value
 verbose                    0 (out of 2)
 version                    FALSE

=head1 OPTIONS

=over

=item I<--column>|I<-c>

The column on which to evaluate partitions.  If the table is currently using
MySQL partitions, the existing partition key will be used.

=item I<--database>|I<-d>

The database to use. Required.

=item I<--help>|I<-h>

Display a short help message and exit.

=item I<--host>|I<-H>

The target MySQL server host.

=item I<--password>|I<-p>

The password of the MySQL user.

=item I<--port>|I<-P>

The port MySQL is listening on.

=item I<--socket>|I<-s>

Use the specified unix socket to connect with. Ignored if --host is specified 
or is anything except 'localhost'.

=item I<--table>|I<-t>

The target table to evaluate.  Required.

=item I<--username>|I<-u>

The MySQL user used to connect

=item I<--verbose>|I<-v>

Increase verbosity level. Can be used up to three times.

=item I<--version>|I<-V>

Display version information and exit.

=back

=head1 SYSTEM REQUIREMENTS

partition_balancer requires the following Perl modules:

  Pod::Usage
  Getopt::Long
  DBI
  DBD::mysql

=head1 BUGS

Please report all bugs and feature requests to 
http://code.google.com/p/partition_balancer

=head1 LICENSE

This program is copyright (c) 2008 Ryan Lowe.
Feedback and improvements are welcome (rlowe@pablowe.net).

THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.

This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation, version 2; OR the Perl Artistic License.  On UNIX and similar
systems, you can issue `man perlgpl' or `man perlartistic' to read these
licenses.

You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place, Suite 330, Boston, MA  02111-1307 USA.

=head1 AUTHOR

Ryan Lowe (rlowe@pablowe.net)

=head1 VERSION

This manual page documents 0.0.1 of partition_balancer

=cut

